package com.bjpowernode.config;

import com.bjpowernode.config.filter.JwtFilter;
import com.bjpowernode.config.handler.DlykAuthenticationFailureHandler;
import com.bjpowernode.config.handler.DlykAuthenticationSuccessHandler;
import com.bjpowernode.config.handler.DlykLogoutSuccessHandler;
import com.bjpowernode.constant.Constants;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.io.PrintWriter;
import java.util.Arrays;

@Configuration
public class Config {

    @Resource
    private DlykAuthenticationSuccessHandler dlykAuthenticationSuccessHandler;

    @Resource
    private DlykAuthenticationFailureHandler dlykAuthenticationFailureHandler;

    @Resource
    private JwtFilter jwtFilter;

    @Resource
    private DlykLogoutSuccessHandler dlykLogoutSuccessHandler;

    /**
     * Spring容器中必须要配置一个秘密加密器，框架需要使用该加密器进行密码的比较
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, CorsConfigurationSource configurationSource) throws Exception {
        return httpSecurity
                .formLogin((formLogin) -> {
                    formLogin.loginProcessingUrl(Constants.LOGIN_URI) //前端vue提交登录请求到该地址上
                            .usernameParameter("loginAct") //登录账号的参数名
                            .passwordParameter("loginPwd") //登录密码的参数名
                            .successHandler(dlykAuthenticationSuccessHandler) //登录成功调用该handler返回结果
                            .failureHandler(dlykAuthenticationFailureHandler); //登录失败调用该handler返回结果
                })

                //跨站伪造请求（网络安全问题）
                .csrf((csrf) -> {
                    csrf.disable(); //前后端分离开发，前端vue页面没有串_csrf这个token串，所以后台要禁用csrf的验证
                })

                //解决跨域问题
                .cors(cors -> {
                    //配置一个bean解决跨域问题
                    cors.configurationSource(configurationSource);
                })

                //禁用session机制，因为是前后端分离开发
                .sessionManagement((sessionManagement) -> {
                    sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
                })

                //加一个jwt验证的filter
                .addFilterBefore(jwtFilter, LogoutFilter.class)

                //配置退出功能
                .logout((logout) -> {
                    logout.logoutUrl("/api/logout") //退出提交到/api/logout地址上
                            .logoutSuccessHandler(dlykLogoutSuccessHandler); //退出成功执行该handler
                })

                .build();
    }

    @Bean
    public CorsConfigurationSource configurationSource() {
        //跨域配置对象，设置哪些来源、请求、头部等可以跨域
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(Arrays.asList("*")); //允许任何来源，http://localhost:8080， http://www.bjpowernode.com
        configuration.setAllowedMethods(Arrays.asList("*")); //允许任何请求方法，post、get、put、delete
        configuration.setAllowedHeaders(Arrays.asList("*")); //允许任何的请求头v token、Authorization、Accept

        UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
        urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", configuration);  //  /api/admin  /api/user/detail
        return urlBasedCorsConfigurationSource;
    }
}
